﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace HexTileBoard
{
    public class Billboard : DrawableGameComponent
    {
        private Effect bbEffect;
        private Texture2D clayTexture, ironTexture, stoneTexture, wheatTexture, woodTexture;

        private Dictionary<HexTileResource, VertexBuffer> vertexBuffers = new Dictionary<HexTileResource, VertexBuffer>();

        public Billboard(Game game)
            : base(game)
        {
            ContentManager content = new ContentManager(this.Game.Services, "Content");

            bbEffect = content.Load<Effect>("Effects/BillboardEffect");
            clayTexture = content.Load<Texture2D>("Textures/Resources/clay_s");
            ironTexture = content.Load<Texture2D>("Textures/Resources/iron_s");
            stoneTexture = content.Load<Texture2D>("Textures/Resources/stone_s");
            wheatTexture = content.Load<Texture2D>("Textures/Resources/wheat_s");
            woodTexture = content.Load<Texture2D>("Textures/Resources/wood_s");

            vertexBuffers.Add(HexTileResource.Clay, null);
            vertexBuffers.Add(HexTileResource.Iron, null);
            vertexBuffers.Add(HexTileResource.Stone, null);
            vertexBuffers.Add(HexTileResource.Wheat, null);
            vertexBuffers.Add(HexTileResource.Wood, null);
        }

        public void DrawBillboards(SimpleCamera p_Camera)
        {
            Vector3 u = p_Camera.ViewMatrix.Up;
            bbEffect.CurrentTechnique = bbEffect.Techniques["CylBillboard"];
            bbEffect.Parameters["tempUp"].SetValue(u);
            bbEffect.Parameters["xWorld"].SetValue(Matrix.Identity);
            bbEffect.Parameters["xView"].SetValue(p_Camera.ViewMatrix);
            bbEffect.Parameters["xProjection"].SetValue(p_Camera.ProjectionMatrix);
            bbEffect.Parameters["xCamPos"].SetValue(p_Camera.CameraPosition);

            this.Game.GraphicsDevice.BlendState = BlendState.AlphaBlend;
            this.Game.GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;

            foreach (HexTileResource r in InstancedDictionaries.resourceListProvider)
            {
                if (r == HexTileResource.None || vertexBuffers[r] == null || vertexBuffers[r].VertexCount == 0)
                    continue;

                switch (r)
                {
                    case HexTileResource.Clay:
                        bbEffect.Parameters["xBillboardTexture"].SetValue(clayTexture); break;
                    case HexTileResource.Iron:
                        bbEffect.Parameters["xBillboardTexture"].SetValue(ironTexture); break;
                    case HexTileResource.Stone:
                        bbEffect.Parameters["xBillboardTexture"].SetValue(stoneTexture); break;
                    case HexTileResource.Wheat:
                        bbEffect.Parameters["xBillboardTexture"].SetValue(wheatTexture); break;
                    case HexTileResource.Wood:
                        bbEffect.Parameters["xBillboardTexture"].SetValue(woodTexture); break;
                }

                this.Game.GraphicsDevice.SetVertexBuffer(vertexBuffers[r]);
                for (int i = 0; i < bbEffect.CurrentTechnique.Passes.Count; i++)
                {
                    bbEffect.CurrentTechnique.Passes[i].Apply();
                    this.Game.GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, vertexBuffers[r].VertexCount);
                }
            }
        }

        public void AddBillboardItem(HexTileResource resourceType, List<TileSimple> positions)
        {
            // Do not draw empty vertices
            //if (resourceType == HexTileResource.None || positions.Count == 0)
            if (positions.Count == 0)
                return;

            // Construct the vertex locations
            VertexPositionTexture[] billboardVertices = new VertexPositionTexture[positions.Count * 6];
            int i = 0;
            for (int j = 0; j < positions.Count; j++)
            {
                billboardVertices[i++] = new VertexPositionTexture(new Vector3(positions[j].Position.X, positions[j].Position.Y + BoardVariables.billboardElevation, positions[j].Position.Z), new Vector2(0, 0));
                billboardVertices[i++] = new VertexPositionTexture(new Vector3(positions[j].Position.X, positions[j].Position.Y + BoardVariables.billboardElevation, positions[j].Position.Z), new Vector2(1, 0));
                billboardVertices[i++] = new VertexPositionTexture(new Vector3(positions[j].Position.X, positions[j].Position.Y + BoardVariables.billboardElevation, positions[j].Position.Z), new Vector2(1, 1));

                billboardVertices[i++] = new VertexPositionTexture(new Vector3(positions[j].Position.X, positions[j].Position.Y + BoardVariables.billboardElevation, positions[j].Position.Z), new Vector2(0, 0));
                billboardVertices[i++] = new VertexPositionTexture(new Vector3(positions[j].Position.X, positions[j].Position.Y + BoardVariables.billboardElevation, positions[j].Position.Z), new Vector2(1, 1));
                billboardVertices[i++] = new VertexPositionTexture(new Vector3(positions[j].Position.X, positions[j].Position.Y + BoardVariables.billboardElevation, positions[j].Position.Z), new Vector2(0, 1));
            }

            // Set the appropriate vertex buffer
            vertexBuffers[resourceType] = new VertexBuffer(this.Game.GraphicsDevice, typeof(VertexPositionTexture), billboardVertices.Length, BufferUsage.WriteOnly);
            vertexBuffers[resourceType].SetData<VertexPositionTexture>(billboardVertices);
        }
    }
}
